package com.dgj.log.service.shiro.impl;

import java.util.List;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.entity.Record;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.Times;
import org.nutz.mvc.Mvcs;

import com.dgj.biz.dao.IUserDao;
import com.dgj.biz.dao.log.ILoginLogDao;
import com.dgj.biz.entitites.User;
import com.dgj.biz.entitites.User.Group;
import com.dgj.biz.entitites.auth.Permission;
import com.dgj.biz.entitites.auth.Role;
import com.dgj.biz.entitites.log.LoginLog;
import com.dgj.log.service.shiro.IShiroUserService;
import com.dgj.utils.db.SqlActuator;
import com.dgj.utils.entries.Result;
import com.dgj.utils.ua.UserAgent;
import com.google.common.collect.Lists;

/**
 * @author 王贵源
 *
 *         create at 2015年4月29日 下午3:49:32
 */
@IocBean(name = "shiroUserService")
public class ShiroUserServiceImpl implements IShiroUserService {

	@Inject
	private PropertiesProxy sqls;
	@Inject
	private Dao dao;
	@Inject
	private IUserDao userDao;

	@Inject
	ILoginLogDao loginLogDao;

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.dgj.titan.boss.service.shiro.IShiroUserService#findByName(java.lang
	 * .String)
	 */
	@Override
	public User findByName(String userName) {
		return userDao.findByCondition(Cnd.where("userName", "=", userName));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.dgj.titan.boss.service.shiro.IShiroUserService#getAllPermissions(int)
	 */
	@SuppressWarnings("unchecked")
	@Override
	public List<Permission> getAllPermissions(int id) {
		List<Permission> permissions = getDirectPermissions(id);
		permissions.addAll(getIndirectPermissions(id));
		return com.dgj.utils.collection.Lists.removeDuplicateWithOrder(permissions);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.dgj.titan.boss.service.shiro.IShiroUserService#getAllPermissionsInfo
	 * (int)
	 */
	@Override
	public List<String> getAllPermissionsInfo(int id) {
		List<String> target = Lists.newArrayList();
		for (Permission permission : getAllPermissions(id)) {
			target.add(permission.getName());
		}
		return target;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.dgj.titan.boss.service.shiro.IShiroUserService#getAllRoles(int)
	 */
	@SuppressWarnings("unchecked")
	@Override
	public List<Role> getAllRoles(int id) {
		List<Role> roles = getDirectRoles(id);// 直接角色
		roles.addAll(getIndirectRoles(id));// 间接角色
		return com.dgj.utils.collection.Lists.removeDuplicateWithOrder(roles);// 去重
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.dgj.titan.boss.service.shiro.IShiroUserService#getDirectPermissions
	 * (int)
	 */
	@Override
	public List<Permission> getDirectPermissions(int id) {
		Sql sql = Sqls.create(sqls.get("find.direct.permissions.by.user.id"));
		sql.params().set("userId", id);
		List<Record> records = SqlActuator.runReport(sql, dao);
		List<Permission> permissions = Lists.newArrayList();
		for (Record record : records) {
			Permission p = record.toPojo(Permission.class);
			p.setName(record.getString("permissionname"));// 此处是由于NUTZ强制别名小写导致的
			permissions.add(p);
		}
		return permissions;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.dgj.titan.boss.service.shiro.IShiroUserService#getDirectRoles(int)
	 */
	@Override
	public List<Role> getDirectRoles(int id) {
		List<Role> roles = Lists.newArrayList();
		Sql sql = Sqls.create(sqls.get("find.direct.roles.by.user.id"));
		sql.params().set("userId", id);
		List<Record> records = SqlActuator.runReport(sql, dao);
		for (Record record : records) {
			Role role = record.toPojo(Role.class);
			role.setDescription(record.getString("description"));
			role.setName(record.getString("rolename"));
			roles.add(role);
		}
		return roles;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.dgj.titan.boss.service.shiro.IShiroUserService#getIndirectPermissions
	 * (int)
	 */
	@Override
	public List<Permission> getIndirectPermissions(int id) {
		// TODO 目前只实现角色权限的查询
		Sql sql = Sqls.create(sqls.get("find.indirect.permissions.by.user.id"));
		sql.params().set("userId", id);
		List<Record> records = SqlActuator.runReport(sql, dao);
		List<Permission> permissions = Lists.newArrayList();
		for (Record record : records) {
			Permission p = record.toPojo(Permission.class);
			p.setName(record.getString("permissionname"));// 此处是由于NUTZ强制别名小写导致的
			permissions.add(p);
		}
		return permissions;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.dgj.titan.boss.service.shiro.IShiroUserService#getIndirectRoles(int)
	 */
	@Override
	public List<Role> getIndirectRoles(int id) {
		// TODO 暂未实现
		return Lists.newArrayList();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.dgj.titan.boss.service.shiro.IShiroUserService#getRolesInfo(int)
	 */
	@Override
	public List<String> getRolesInfo(int id) {
		List<String> target = Lists.newArrayList();
		for (Role role : getAllRoles(id)) {
			target.add(role.getName());
		}
		return target;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.dgj.titan.boss.service.shiro.IShiroUserService#login(java.lang.String
	 * , java.lang.String)
	 */
	@Override
	public Result login(String userName, String password) {
		try {
			User user = findByName(userName);
			if (!(user.getUserType().equals(Group.DGJ))) {
				return Result.fail("非管理人员不能登录");
			}
			Subject currentUser = SecurityUtils.getSubject();
			UsernamePasswordToken token = new UsernamePasswordToken(userName, password);
			token.setRememberMe(true);
			currentUser.login(token);
			/**
			 * 记录登录信息
			 */
			LoginLog log = new LoginLog();
			log.setUserId(user.getId());
			UserAgent ua = new UserAgent(Mvcs.getReq().getHeader("user-agent"));
			String ip = Lang.getIP(Mvcs.getReq());
			log.setLoginIp(ip);
			log.setOs(ua.getOperatingSystem());
			log.setBrowser(ua.getBrowser());
			loginLogDao.save(log);
			user.setLastLoginTime(Times.now());
			user.setLoginIp(ip);
			userDao.update(user);
			return Result.success().addData("loginUser", user);

		} catch (LockedAccountException e) {
			return Result.fail("账户被锁定");
		} catch (AuthenticationException e) {
			return Result.fail("密码错误或用户不存在");
		} catch (Exception e) {
			e.printStackTrace();
			return Result.fail("登录失败");
		}
	}

}
